#include "file_util.h" 
#include <stdarg.h> 
#include <iostream>
#include <time.h>
/**
The _fsopen function opens the file specified by filename as a stream and prepares the file for subsequent shared reading or writing, as defined by the mode and shflag arguments. _wfsopen is a wide-character version of _fsopen; the filename and mode arguments to _wfsopen are wide-character strings. _wfsopen and _fsopen behave identically otherwise.

The character string mode specifies the type of access requested for the file, as shown in the following table.

REMARKS
Term    Definition
"r" Opens for reading. If the file does not exist or cannot be found, the _fsopen call fails.
"w" Opens an empty file for writing. If the given file exists, its contents are destroyed.
"a" Opens for writing at the end of the file (appending); creates the file first if it does not exist.
"r+"    Opens for both reading and writing. (The file must exist.)
"w+"    Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.
"a+"    Opens for reading and appending; creates the file first if it does not exist.
Use the "w" and "w+" types with care, as they can destroy existing files.

When a file is opened with the "a" or "a+" access type,
all write operations occur at the end of the file.
The file pointer can be repositioned using fseek or rewind,
but it is always moved back to the end of the file before any write operation is carried out.
Thus, existing data cannot be overwritten. When the "r+", "w+", or "a+" access type is specified,
both reading and writing are allowed (the file is said to be open for update).
However, when switching between reading and writing, there must be an intervening fsetpos, fseek, or rewind operation.
The current position can be specified for the fsetpos or fseek operation,
if desired. In addition to the above values, one of the following characters
can be included in mode to specify the translation mode for new lines, and for file management.

*/

bool CFileUtil::openFile(const char* filePath, const char* mode) {
    if (m_file) {
        std::fclose(m_file);
        m_file = nullptr;
    }
    m_file = _fsopen(filePath, mode, _SH_DENYNO);
    m_strFileName = filePath;
    return m_file != nullptr;
}
bool CFileUtil::closeFile() {
    if (m_file) {
        std::fflush(m_file);
        std::fclose(m_file);
        m_file = nullptr;
        return true;
    }
    return false;
}

std::size_t CFileUtil::readSome(char* strOut, std::size_t n) {
    if (m_file == nullptr)
        return -1;
    auto sizeRead = fread((void*)(strOut), 1, n, m_file);
    if (sizeRead != n) {
        auto erroId = ferror(m_file);
        auto pos = ftell(m_file);
        std::cout << "readSome ERROR [" << erroId << "]pos<" << pos << ">\n";

    }
    return sizeRead;
}

std::size_t CFileUtil::readSome(std::string& strOut, std::size_t n) {
    if (m_file == nullptr)
        return -1;
    strOut.reserve(n);
    strOut.resize(n);
    auto sizeRead = fread((void*)const_cast<const char*>(strOut.c_str()), 1, n, m_file);
    return sizeRead;
}

std::size_t CFileUtil::readWholeFile(std::string& strOut) {
    if (m_file == nullptr)
        return -1;
    auto size = getFileSize();
    if (size <= 0) {
        return -1;
    }
    fseek(m_file, 0, SEEK_SET);///从头开始读取 
    if (strOut.size() < size) {
        strOut.resize(size);
    }
    auto sizeRead = fread((void*)const_cast<const char*>(strOut.c_str()), 1, size, m_file);
    if (sizeRead != size) {
        return -1;
    }
    return sizeRead;
}
std::size_t CFileUtil::readWholeFile(char* buf, std::size_t& sizeOut) {
    if (m_file == nullptr)
        return -1;
    auto size = getFileSize();
    if (size <= 0) {
        return -1;
    }
    fseek(m_file, 0, SEEK_SET);///从头开始读取 
    auto sizeRead = fread((void*)buf, 1, size, m_file);
    if (sizeRead != size) {
        return -1;
    }
    sizeOut = size;
    return sizeRead;
}
std::size_t CFileUtil::readAllLines(std::vector<std::string>& vecOut) {
    //std::getline()
    if (m_file == nullptr)
        return -1;

    fseek(m_file, 0, SEEK_SET);///从头开始读取 
    int c = 0;
    std::string strLine;
    strLine.reserve(1024);
    c = fgetc(m_file);
    while (c != EOF) {
        if (c != '\n') {
            if (c != '\r') {
                strLine.push_back((const char)(c));
            } else {
                ///考虑"\r\n"情况
            }
        } else {
            vecOut.push_back(strLine);
            strLine.clear();
        }
        c = fgetc(m_file);
    }
    if (strLine.size()) {
        vecOut.push_back(strLine);
    }
    return vecOut.size();
}

std::size_t CFileUtil::appendWrite(const char* data, std::size_t size) {
    if (m_file == nullptr)
        return -1;
    fseek(m_file, 0L, SEEK_END);
    auto sizew = fwrite(data, 1, size, m_file);
    // forceFlush();
    return sizew;
}

void CFileUtil::forceFlush() {
    std::fflush(m_file);
}

std::size_t CFileUtil::writeLines(const std::vector<std::string>& vecOut) {
    if (m_file == nullptr)
        return -1;
    auto size = 0;
    for (auto& str : vecOut) {
        appendWrite(str.c_str(), str.length());
        appendWrite("\n", 1);
        size += str.length() + 1;
    }
    return size;
}

std::size_t CFileUtil::truncateWrite(const std::string& strContent) {
    return truncateWrite(strContent.c_str(), strContent.length());
}

std::size_t CFileUtil::truncateWrite(const char* data, std::size_t size) {
    fseek(m_file, 0, SEEK_SET);///从头开始读取 
    auto sizew = fwrite(data, 1, size, m_file);
    if (sizew != size) {
        std::cout << "CFileUtil::writeTruncate sizeOrig[" << size << "]writed size [" << sizew << "]\n";
    }
    return sizew;
}

std::size_t CFileUtil::writeSome(const char* data, std::size_t size) {
    auto sizew = fwrite(data, 1, size, m_file);
    if (sizew != size) {
        std::cout << "CFileUtil::writeSome sizeOrig[" << size << "]writed size [" << sizew << "]\n";
    }
    return sizew;
}

std::size_t CFileUtil::writeFormat(const char* format, ...) {
    va_list args;
    va_start(args, format);
    static char szBuffer[1024 * 8] = {0};
    int size = vsprintf_s(szBuffer, sizeof(szBuffer), format, args);
    va_end(args);
    auto sizeWrited = appendWrite(szBuffer, size);
    memset(szBuffer, 0, size);
    return sizeWrited;

}
std::size_t CFileUtil::getFileSize() {
    if (m_file == nullptr)
        return -1;
    long curpos = 0, length = 0;
    curpos = ftell(m_file);
    fseek(m_file, 0L, SEEK_END);
    length = ftell(m_file);
    fseek(m_file, curpos, SEEK_SET);
    return (std::size_t)length;
}

bool CFileUtil::fseekRw(std::size_t startPos) {
    if (startPos > getFileSize()) {
        return false;
    }
    int ret = fseek(m_file, startPos, SEEK_SET);
    std::cout << "fseekTo [" << startPos << "]ret[" << ret << "]\n";
    return true;
}
